//
// Created by 49647 on 2022/4/10.
//


#include <cassert>
#include <iostream>
#include "log.h"
#include "AMessage.h"
#include "AHandler.h"

#define LOG_TAG "AMessage"
using namespace std;

shared_ptr<AReplyToken> AReplyToken::Create(const shared_ptr<ALooper> &looper) {
    return shared_ptr<AReplyToken>(new AReplyToken(looper));
}

bool AReplyToken::retrieveReply(shared_ptr<AMessage> *reply) {
    if (mReplied) {
        *reply = mReply;
        mReply.reset();
    }
    return mReplied;
}

int AReplyToken::setReply(const shared_ptr<AMessage> &reply) {
    if (mReplied) {
        LOGE("trying to post a duplicate reply");
        return -EBUSY;
    }
    assert(mReply == nullptr);
    mReply = reply;
    mReplied = true;
    return 0;
}

shared_ptr<AMessage> AMessage::Create() {
    return shared_ptr<AMessage>(new AMessage());
}

shared_ptr<AMessage> AMessage::Create(uint32_t what, const shared_ptr<AHandler> &handler) {
    return shared_ptr<AMessage>(new AMessage(what, handler));
}

void AMessage::setTargetHandler(const std::shared_ptr<AHandler> &handler) {
    if (handler == nullptr) {
        mHandler.reset();
        mLooper.reset();
    } else {
        mHandler = handler;
        mLooper = handler->getLooper();
    }
}

void AMessage::deliver() {
    shared_ptr<AHandler> handler = mHandler.lock();
    if (handler == nullptr) {
        LOGW("failed to deliver message as target handler is gone");
        return;
    }
    handler->deliverMessage(shared_from_this());
}

int AMessage::post(int64_t delayUs) {
    shared_ptr<ALooper> looper = mLooper.lock();
    if (looper == nullptr) {
        LOGW("failed to post message as target looper for handler is gone");
        return -ENOENT;
    }
    looper->post(shared_from_this(), delayUs);
    return 0;
}

int AMessage::postAndAwaitResponse(shared_ptr<AMessage> *response) {
    shared_ptr<ALooper> looper = mLooper.lock();
    if (looper == nullptr) {
        LOGW("failed to post message as target looper for handler is gone");
        return -ENOENT;
    }

    shared_ptr<AReplyToken> token = looper->createReplyToken();
    if (token == nullptr) {
        LOGE("failed to create reply token");
        return -ENOMEM;
    }
    setValue("replyID", token);

    looper->post(shared_from_this(), 0);
    return looper->awaitResponse(token, response);
}

int AMessage::postReply(const shared_ptr<AReplyToken> &replyToken) {
    if (replyToken == nullptr) {
        LOGW("failed to post reply to a NULL token");
        return -ENOENT;
    }
    shared_ptr<ALooper> looper = replyToken->getLooper();
    if (looper == nullptr) {
        LOGW("failed to post reply as target looper is gone");
        return -ENOENT;
    }
    return looper->postReply(replyToken, shared_from_this());
}

bool AMessage::senderAwaitsResponse(shared_ptr<AReplyToken> *replyToken) {
    bool found = getValue<shared_ptr<AReplyToken>>("replyID", replyToken);
    if (!found) {
        return false;
    }
    return *replyToken != nullptr;
}

shared_ptr<AMessage> AMessage::dup() const {
    shared_ptr<AMessage> msg = AMessage::Create(mWhat, mHandler.lock());
    msg->mItems = mItems;
    return msg;
}

void AMessage::print() const {
    cout << "AMessage(what = " << mWhat << "): {" << endl;
    for (auto &item : mItems) {
        cout << item.first << ", type=" << item.second.type().name() << endl;
    }
    cout << "}" << endl;
}
